package com.example.cash_register.service;

import com.example.cash_register.mapper.OrderItemMapper;
import com.example.cash_register.mapper.OrderMapper;
import com.example.cash_register.mapper.ProductMapper;
import com.example.cash_register.model.order.Order;
import com.example.cash_register.model.order.OrderDetail;
import com.example.cash_register.model.order.OrderItem;
import com.example.cash_register.model.order.OrderStatus;
import com.example.cash_register.model.product.Product;
import com.example.cash_register.model.user.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.time.Instant;
import java.util.*;

@Slf4j
@Service
public class OrderService {
    private final ProductMapper productMapper;
    private final OrderMapper orderMapper;
    private final OrderItemMapper orderItemMapper;

    @Autowired
    public OrderService(ProductMapper productMapper, OrderMapper orderMapper, OrderItemMapper orderItemMapper) {
        this.productMapper = productMapper;
        this.orderMapper = orderMapper;
        this.orderItemMapper = orderItemMapper;
    }

    @Transactional
    public Order create(User user, Map<Integer,Integer> toBoughtProductMap) {
        log.debug("toBoughtProductMap = {}", toBoughtProductMap);
        Map<Integer,Product> productMap = 确认商品库存是否足够(toBoughtProductMap);
        log.debug("productMap = {}",productMap);
        商品减库存(toBoughtProductMap);
        Order order = 创建订单记录(user,productMap,toBoughtProductMap);
        插入订单项(order,productMap,toBoughtProductMap);
        return order;
    }

    private Order 创建订单记录(User user, Map<Integer, Product> productMap,Map<Integer,Integer> toBoughtProductMap) {
        String uuid = generateUUID();
        Timestamp createdAt = Timestamp.from(Instant.now());

        int payable = 计算应付金额(productMap,toBoughtProductMap);
        int actual = 计算实际支付金额(productMap,toBoughtProductMap);
        OrderStatus status = OrderStatus.未支付;
        Order order = new Order(user.getUserId(),uuid,createdAt,payable,actual,status);

        orderMapper.insert(order);
        log.debug("order = {}",order);
        return order;
    }

    private void 插入订单项(Order order,Map<Integer,Product> productMap,Map<Integer,Integer> toBoughtProductMap) {
        Set<Integer> productIdSet = productMap.keySet();
        Set<OrderItem> orederItemSet = new HashSet<>();
        for (Integer productId : productIdSet) {
            Product product = productMap.get(productId);
            int number = toBoughtProductMap.get(productId);
            OrderItem orderItem = new OrderItem(order,product,number);
            orederItemSet.add(orderItem);
        }
        orderItemMapper.insertBatch(orederItemSet);
    }

    private int 计算实际支付金额(Map<Integer, Product> productMap, Map<Integer, Integer> toBoughtProductMap) {
        Set<Integer> productSet = productMap.keySet();
        int sum = 0;
        for(Integer productId : productSet) {
            int number = toBoughtProductMap.get(productId);
            Product product = productMap.get(productId);
            int price = product.getPrice();
            double discount = product.getDiscount() / 100.0;
            sum += (int)(number * price * discount);
        }
        return sum;
    }

    private int 计算应付金额(Map<Integer, Product> productMap, Map<Integer, Integer> toBoughtProductMap) {
        Set<Integer> productIdSet = productMap.keySet();
        int sum = 0;
        for(Integer productId : productIdSet) {
            int number = toBoughtProductMap.get(productId);
            Product product = productMap.get(productId);
            int price = product.getPrice();
            int productPayable = price * number;
            sum += productPayable;
        }
        return sum;
    }

    private String generateUUID() {
        String s = UUID.randomUUID().toString();
        return s.replace("-","");
    }

    private void 商品减库存(Map<Integer,Integer> toBoughtProductMap) {
        for (Map.Entry<Integer,Integer> entry : toBoughtProductMap.entrySet()) {
            int productId = entry.getKey();
            int number = entry.getValue();
            productMapper.decrementStockByProductId(productId,number);
        }
    }

    private Map<Integer,Product> 确认商品库存是否足够(Map<Integer,Integer> toBoughtProductMap) {
        Set<Integer> productIdSet = toBoughtProductMap.keySet();
        List<Product> products = productMapper.selectProductListByProductIdSet(productIdSet);
        Map<Integer,Product> productMap = new HashMap<>();
        for (Product product : products) {
            productMap.put(product.getProductId(),product);
        }
        for (Integer productId : productIdSet) {
            int number = toBoughtProductMap.get(productId);
            Product product = productMap.get(productId);
            if(number > product.getStock()) {
                throw new RuntimeException(product.getProductId().toString());
            }
        }
        return productMap;
    }

    @Transactional
    public void confirm(int orderId) {
        Timestamp finishedAt = Timestamp.from(Instant.now());
        OrderStatus status = OrderStatus.已支付;
        orderMapper.updateConfirm(orderId,finishedAt,status);
    }

    @Transactional
    public void cancel(int orderId) {
        List<OrderItem> orderItemList = orderItemMapper.selectByOrderId(orderId);
        Map<Integer,Integer> toBoughtProductMap = new HashMap<>();
        for (OrderItem orderItem : orderItemList) {
            int productId = orderItem.getProductId();
            int number = orderItem.getProductNumber();
            toBoughtProductMap.put(productId,number);
        }
        orderItemMapper.deleteByOrderId(orderId);
        orderMapper.deleteByOrderId(orderId);
        for (Map.Entry<Integer,Integer> entry : toBoughtProductMap.entrySet()) {
            int productId = entry.getKey();
            int number = entry.getValue();
            productMapper.incrementStockByProductId(productId,number);
        }
    }
    public OrderDetail query(String uuid) {
        OrderDetail order = orderMapper.selectByUUID(uuid);
        order.setItemList(orderItemMapper.selectAllByOrderId(order.getOrderId()));
        return order;
    }

    public List<Order> getList() {
        return orderMapper.selectAll();
    }
}
